package com.zhdl.hardware.motor.buke.repository.impl;

import cn.hutool.core.util.HexUtil;
import com.google.common.eventbus.Subscribe;
import com.project.command.faq.event.behavior.BehaviorPerform;
import com.project.command.instruction.strategy.process.data.AfterStrategyParam;
import com.project.common.util.ByteHelper;
import com.project.common.util.DelayUtil;
import com.zhdl.common.eventbus.center.EventBusCenter;
import com.zhdl.hardware.motor.buke.repository.BukeMotorCmdHandleDao;
import com.zhdl.modules.tools.CommonCallback;
import com.zhdl.network.modbus.ModbusRtuRespPkg;
import com.zhdl.network.modbus.dto.ModbusDto;
import com.zhdl.network.modbus.request.WriteSingleKeepRegisterReq;
import com.zhdl.network.strategy.common.ProtocolContext;
import com.zhdl.network.strategy.modbusrtu.ModbusRtuStrategy;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class BukeMotorCmdHandleDaoImpl implements BukeMotorCmdHandleDao {

    /**
     * 汇川电机-串口
     */
    public String port;
    /**
     * 通信协议处理
     */
    public ProtocolContext protocolContext;
    /**
     * Callback 回调管理
     */
    public Map<String, CommonCallback<byte[]>> commonCallbackMap = new ConcurrentHashMap<>();

    public BukeMotorCmdHandleDaoImpl(String port, BehaviorPerform behaviorPerform){
        EventBusCenter.getEventBus().register(this);
        protocolContext = new ProtocolContext(new ModbusRtuStrategy(port, behaviorPerform));
        this.port = port;
    }

    @Subscribe
    public void dataReception(AfterStrategyParam event) {

        /* 判断当前串口 */
        if (port.equals(event.getPortKey())) {
            /* 获取电机指令返回的数据 */
            //此处接收串口或网口客户端回应代码,并处理
            List<ModbusDto> list = event.getNewData();
            ModbusDto modbusDto = list.get(0);

            String instruction = event.getInstruction();
            instruction = instruction.replaceAll(" ", "");
            instruction = instruction.toUpperCase();
            for (String cmd : commonCallbackMap.keySet()) {
                String temp = cmd.toUpperCase();
                if (temp.contains(instruction)) {
                    commonCallbackMap.get(cmd).statusCallback(modbusDto.getUnitBuff());
                    commonCallbackMap.remove(cmd);
                }
            }
        }
    }


    /**
     * 0x03 获取电机状态(包括Y轴与X轴)
     * 0x3200 状态字节显示驱动器的状态
     * 读取状态字，9437 表示原点找到
     * 01 03 32 00 00 01 8A B2
     *
     * @param slaveStationId 从站Id
     */
    @Override
    public void bukeMotorStatus(String slaveStationId, CommonCallback<String> callback) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3200");
        //设置 电机-寄存器个数
        req.setWriteValue("0001");
        try {
            //设置 电机-功能码 03 读单个寄存器
            byte[] bytes = ModbusRtuRespPkg.ReadSingleKeepRegister(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 0x06 写单个线圈寄存器 设置运动方式
     * 0x3100  控制字  先 F  后 1F   绝对位置运动时，上次目标位置到后，电机开始运动
     * 先 2F 后 3F   绝对位置运动时，电机立即开始运动
     * 01 06 31 00 00 2F C6 EA   01 06 31 00 00 3F C7 26
     *
     * @param slaveStationId 从站Id
     * @param motorRunType   运动方式
     */
    @Override
    public void bukeSetRunType(String slaveStationId, String motorRunType) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3100");
        //设置 电机-运动方式
        req.setWriteValue(motorRunType);
        try {
            //设置 电机-功能码 06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 0x10 写多个线圈寄存器 设置梯形速度
     * 0x4A00  梯形速度    值200RPM (00 00 00 32) (50)
     * 01 10 4A 00 00 02 04 00 00 00 32 3D 19
     *
     * @param slaveStationId 从站Id
     * @param tSpeedValue    梯形速度
     */
    @Override
    public void bukeSetRunTSpeed(String slaveStationId, Integer tSpeedValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("4A00");
        //设置 电机-梯形速度
        byte[] dataArray = ModbusRtuRespPkg.intToByte4(tSpeedValue);
        req.setWriteValue(ByteHelper.bytesArrayToHexString(dataArray));

        try {
            //设置 电机-功能码 10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 0x10 写多个线圈寄存器 设置目标位置
     * 0x4000  目标位置    值50000DEC (C3 50 00 00)
     * 01 10 4A 00 00 02 04 00 00 00 32 3D 19
     *
     * @param slaveStationId   从站Id
     * @param destinationValue 脉冲数
     */
    @Override
    public void bukeSetRunDistance(String slaveStationId, Integer destinationValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("4000");
        //设置 电机-梯形速度
        byte[] dataArray = ModbusRtuRespPkg.intToByte4(destinationValue);
        req.setWriteValue(ByteHelper.bytesArrayToHexString(dataArray));
        try {
            //设置 电机-功能码 10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 步科电机-电机找原点
     *
     * @param slaveStationId 从站Id
     */
    @Override
    public void bukeBackOrigin(String slaveStationId) {
        /*
            1.设定工作模式为原点模式: 0x3500   0x6
            01 06 35 00 00 06 06 04
         */
        SetHomeWork(slaveStationId);

        /*
            2.寻找原点模式:0x4D00
            发送: 01 06 4D 00 00 14 9E A9
         */
        SetHomeType(slaveStationId);

        /*
            3.寻找转折信号时的速度
            发送: 01 10 50 10 00 02 04 00 00 00 32 8F 75
         */
        setHomeTSpeed(slaveStationId, 200);

        /*
            4.寻找原点时的速度:0x5020  150RPM
            发送:01 10 50 20 00 02 04 80 00 00 25 E5 AF
         */
        setHomeSpeed(slaveStationId, 150);

        /*
            5.设置控制字运动方式
            锁紧电机轴，电机开始运动  控制字0x3100  先0xF后001F
         */
        setHomeRunType(slaveStationId, "000F");

        setHomeRunType(slaveStationId, "001F");
    }

    /**
     * 步科电机-电机移动
     * 设置位置模式1,控制电机寻找目标位置
     *
     * @param slaveStationId   从站Id
     * @param destinationValue 脉冲数
     * @param tSpeedValue      梯形速度
     */
    @Override
    public void bukeMotorRun(String slaveStationId, Integer destinationValue, Integer tSpeedValue) {

        bukeSetRunType(slaveStationId, "000F");

        /*
            1.设置位置模式
         */
        setRunWorkType(slaveStationId);

        /*
            2.设置目标位置
         */
        bukeSetRunDistance(slaveStationId, destinationValue);

        /*
            3.设置梯形速度
            速度 RPM 需要转换为内部单位
            DEC=[(RPM*512*60000)/1875]
         */
        tSpeedValue = (tSpeedValue*512*60000)/1875;
        bukeSetRunTSpeed(slaveStationId, tSpeedValue);

        /*
            4.设置控制字运动方式
            先 2F 后 3F  绝对位置运动时,电机立即开始运动
            先 4F 后 5F  相对定位
         */
        bukeSetRunType(slaveStationId, "002F");

        DelayUtil.delayedExecution(100, () ->
                bukeSetRunType(slaveStationId, "003F"));
    }

    /**
     * 步科电机-电机停止
     */
    @Override
    public void bukeMotorReady(String slaveId) {
        bukeSetRunType(slaveId, "000F");
    }

    /**
     * 步科电机-电机停止
     */
    @Override
    public void bukeMotorNoReady(String slaveId) {
        bukeSetRunType(slaveId, "0006");
    }


    /**
     * 设定工作模式位原点模式
     *
     * @param slaveStationId 从站Id
     */
    public String SetHomeWork(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3500");
        //设置 电机-电机的工作模式
        req.setWriteValue("0006");
        try {
            //功能码06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 设定工作模式位原点模式
     *
     * @param slaveStationId 从站Id
     */
    public String SetHomeType(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("4D00");
        //设置 电机-电机的找原点`模式
        req.setWriteValue("0018");

        try {
            //功能码06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 转折信号时的速度:0x5010 200RPM
     *
     * @param slaveStationId 从站Id
     * @param tSpeedValue    梯形速度
     */
    public String setHomeTSpeed(String slaveStationId, Integer tSpeedValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("5010");
        //设置 电机-找原点的速度 00000020
        req.setWriteValue(ByteHelper.byteToHexStr(tSpeedValue.byteValue()));

        try {
            //功能码 0x10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 原点时的速度:0x5020  150RPM
     *
     * @param slaveStationId 从站Id
     * @param tSpeedValue    梯形速度
     */
    public String setHomeSpeed(String slaveStationId, Integer tSpeedValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("5020");
        //设置 电机-找原点的速度 80000020
        req.setWriteValue(ByteHelper.byteToHexStr(tSpeedValue.byteValue()));

        try {
            //功能码 0x10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

    /**
     * 锁紧电机轴，电机开始运动 --- 电机找原点运动
     * 控制字0x3100  先0xF后001F
     *
     * @param slaveStationId 从站Id
     * @param motorRunType   电机运动类型
     */
    public String setHomeRunType(String slaveStationId, String motorRunType) {

        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3100");
        //设置 电机-运动方式
        req.setWriteValue(motorRunType);
        try {
            //设置 电机-功能码 06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }


    /**
     * 锁紧电机轴，电机开始运动 ---- 电机运动
     * 控制字0x3500  先0xF后001F
     *
     * @param slaveStationId 从站Id
     */
    public String setRunWorkType(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3500");
        //设置 电机-运动方式
        req.setWriteValue("0001");
        try {
            //设置 电机-功能码 06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            protocolContext.sendCmd(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

}
